using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using Rites;
using Rites.Networking;

public class UIChatbox : UIElement
{
    private Texture2D _frameTexture = null;
    private SpriteFont ChatFont;
    protected int _maxTypingBuffer;
    private string _internalBuffer = string.Empty;
    private string _displayInternalBuffer = string.Empty;
    public event TextEventDelegate TextCommand;
    private ArrayList _displayBuffer = new ArrayList();
    private string _indentCharacter = "    ";
    Rectangle framePosition;
    private const int TEXT_LEFT_OFFSET = 35; //Const specific to this control

    public string PlayerName { get; set; }

    public UIChatbox(int x, int y, int width, int height, int typingBuffer)
    {
        ElementLeft = x;
        ElementTop = y;
        ElementWidth = width;
        ElementHeight = height;
        _maxTypingBuffer = typingBuffer;
        framePosition = new Rectangle(ElementLeft, ElementTop, ElementWidth, ElementHeight);
    }

    public bool InCommandMode { get; set; }

    public bool InChatMode { get; set; }

    private string _chatBuffer;

    public string ChatBuffer
    {
        get { return _chatBuffer; }
        set { _chatBuffer = value; }
    }

    private ArrayList _chatLog = new ArrayList();

    public ArrayList ChatLog
    {
        get { return _chatLog; }
        set { _chatLog = value; }
    }

    public void LoadContent(ContentManager content)
    {
        ChatFont = content.Load<SpriteFont>("Fonts//RitesChat");
        _frameTexture = content.Load<Texture2D>("Textures//ChatFrame");
    }

    public void HandleInput(InputHandler ih)
    {
        if (InChatMode || InCommandMode)
            ProcessText(ih, PlayerName);
        else
        {
            if (ih.KeyPressed(Keys.Enter))
                InChatMode = true;
            else if (ih.KeyPressed(Keys.OemQuestion))
                InCommandMode = true;
        }
    }

    public void AddChat(string chatString, string plrName)
    {
        chatString = plrName + ": " + chatString;
        AddChat(chatString, false);
    }

    public void AddChat(string chatString)
    {
        ChatLog.Insert(0, chatString);
        PopulateDisplayBuffer(chatString);
    }

    public void AddChat(string chatString, bool checkForSpam)
    {
        if (checkForSpam && this.SameLastLine(chatString))
            return;
        else
        {
            ChatLog.Insert(0, chatString);
            PopulateDisplayBuffer(chatString);
        }
    }

    public bool SameLastLine(string newInput)
    {
        if (ChatLog.Count > 0)
            return ((string)ChatLog[0] == newInput);
        else
            return false;
    }

    private string ProcessText(InputHandler inputHandler, string plrName)
    {
        if (inputHandler.KeyPressed(Keys.Enter))
        {
            _internalBuffer += inputHandler.FlushBuffer();

            if (_internalBuffer.Length > 0)
            {
                _internalBuffer = _internalBuffer.Replace("\n", "");
                if (_internalBuffer.Length > 0)
                {
                    if (InChatMode)
                    {
                        //AddChat(_internalBuffer, plrName);
                        this.TextCommand(RitesProtocol.Chat, _internalBuffer);
                    }
                    else if (InCommandMode)
                    {
                        //AddChat(_internalBuffer);
                        this.TextCommand(RitesProtocol.TextCommand, _internalBuffer);
                    }
                }
            }

            _internalBuffer = String.Empty;
            _displayInternalBuffer = String.Empty;
            InChatMode = InCommandMode = false;
        }
        else if (inputHandler.KeyPressed(Keys.Escape))
        {
            _internalBuffer = String.Empty;
            _displayInternalBuffer = String.Empty;
            InChatMode = InCommandMode = false;
            inputHandler.FlushBuffer();
        }
        else
        {
            string tempString = inputHandler.FlushBuffer();
            if (tempString.Length > 0)
            {
                if ((tempString.Length + _internalBuffer.Length <= _maxTypingBuffer) || (tempString.LastIndexOf("\b") >= 0))
                {
                    _internalBuffer += tempString;
                    _internalBuffer = ProcessBackspaceCharacters(_internalBuffer);

                    if (ChatFont.MeasureString(_internalBuffer).X > ElementWidth - 60)
                    {
                        _displayInternalBuffer = _internalBuffer.Substring(_internalBuffer.Length - _displayInternalBuffer.Length, _displayInternalBuffer.Length);
                    }
                    else
                        _displayInternalBuffer = _internalBuffer;
                }
            }
        }

        return _internalBuffer;
    }

    private string ProcessBackspaceCharacters(string inputString)
    {
        int foundIndex = inputString.LastIndexOf("\b");
        while (foundIndex > 0)
        {
            inputString = inputString.Remove(inputString.IndexOf("\b") - 1, 2);
            foundIndex = inputString.LastIndexOf("\b");
        }

        return inputString.Replace("\b", "");
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        int outputY = 0;

        //Draw background texture
        spriteBatch.Draw(_frameTexture, framePosition, Color.White);

        //Here we render chat lines that have already been added to the chat box
        if (ChatLog.Count > 0)
        {
            //Enclose in a try because this collection might be modified by another thread, potentially problematic
            //This should be handled better, look into lock() method
            try
            {
                for (int lineIndex = 0; lineIndex < _displayBuffer.Count; lineIndex++)
                {
                    outputY = ElementTop - 2 + ElementHeight - ((lineIndex+2) * ChatFont.LineSpacing);
                    if (outputY <= ElementTop) //draw height limit reached?
                        break;

                    //Old font color: new Color(90, 0, 0)
                    spriteBatch.DrawString(ChatFont, (string)_displayBuffer[lineIndex], new Vector2(ElementLeft + TEXT_LEFT_OFFSET, outputY), new Color(0, 0, 90));
                }
            }
            catch (Exception)
            {
            }
        }

        //Here we render text that the player is still editing, has not been committed to the chatbox yet
        if (InChatMode || InCommandMode)
        {
            bool showCursor = ((DateTime.Now.Millisecond / 250) % 2 == 0);
            string tempBuffer = _displayInternalBuffer + (showCursor ? "_" : "");

            outputY = ElementTop - 2 + ElementHeight - ChatFont.LineSpacing;
            spriteBatch.DrawString(ChatFont, tempBuffer, new Vector2(ElementLeft + TEXT_LEFT_OFFSET, outputY), new Color(90, 0, 0));
        }
    }

    private void PopulateDisplayBuffer(string inputString)
    {
        int lineBreakMarker = 0;
        int previousLineBreak = 0;
        int foundStrings = 0;
        bool spaceFoundYet = false;
        for (int x = 1; x <= inputString.Length; x++)
        {
            if (ChatFont.MeasureString(inputString.Substring(previousLineBreak, x - previousLineBreak)).X < ElementWidth - 50 - (foundStrings > 0 ? 20 : 0)) //Last bit added - (foundStrings > 0 ? 20:0) so we can indent word wrapped lines.
            {
                //We're still inside limits
                if (inputString[x - 1] == ' ')
                {
                    spaceFoundYet = true;
                    lineBreakMarker = x;
                }
                else
                {
                    if (!spaceFoundYet)
                        lineBreakMarker = x;
                }

                if (x == inputString.Length) //At the end of string
                {
                    if (foundStrings == 0)
                        _displayBuffer.Insert(0, inputString);
                    else
                        _displayBuffer.Insert(0, _indentCharacter + inputString.Substring(previousLineBreak));
                }
            }
            else
            {
                _displayBuffer.Insert(0, (foundStrings > 0 ? _indentCharacter : "") + inputString.Substring(previousLineBreak, lineBreakMarker - previousLineBreak));
                foundStrings++;
                previousLineBreak = lineBreakMarker;
                x = lineBreakMarker;
                lineBreakMarker = 0;
                spaceFoundYet = false;
            }
        }
    }
}
